package org.force4spring.support;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.DynaBean;
import org.apache.commons.beanutils.DynaClass;
import org.apache.commons.beanutils.DynaProperty;

public class SObjectDynaBean extends HashMap<String,Object> implements DynaBean {
	private SObjectDynaClass dynaClass;

	SObjectDynaBean(SObjectDynaClass dynaClass) {
		this.dynaClass = dynaClass;
	}

	/**
	 * @see org.apache.commons.beanutils.DynaBean#contains(java.lang.String,
	 *      java.lang.String)
	 */
	public boolean contains(String name, String key) {
		return false;
	}

	/**
	 * @see org.apache.commons.beanutils.DynaBean#get(java.lang.String, int)
	 */
	public Object get(String name, int index) {
		return null;
	}

	/**
	 * @see org.apache.commons.beanutils.DynaBean#get(java.lang.String,
	 *      java.lang.String)
	 */
	public Object get(String name, String key) {
		Map map = getMappedValue(name);
		return map.get(key);
	}

	/**
	 * @see org.apache.commons.beanutils.DynaBean#get(java.lang.String)
	 */
	public Object get(String name) {
		return get(this, name);
	}
	
	private Object getInternal(String name) {
		name = name.trim();
		name = name.toLowerCase();
		return super.get(name);
	}
	
	private Object get(SObjectDynaBean target, String name) {
		int dotPos = name.indexOf('.');
		String more = null;
		if (dotPos > 0) {
			more = name.substring(dotPos + 1, name.length());
			name = name.substring(0, dotPos);
		}
		Object value = target.getInternal(name);
		if ((more != null) && (value instanceof SObjectDynaBean)) {
			return get((SObjectDynaBean)value, more);
		}
		return value;
	}
	

	/**
	 * @see java.util.HashMap#get(java.lang.Object)
	 */
	@Override
	public Object get(Object key) {
		return get(key.toString());
	}

	/**
	 * @see org.apache.commons.beanutils.DynaBean#getDynaClass()
	 */
	public DynaClass getDynaClass() {
		return dynaClass;
	}

	/**
	 * @see org.apache.commons.beanutils.DynaBean#remove(java.lang.String,
	 *      java.lang.String)
	 */
	public void remove(String name, String key) {
		Map map = getMappedValue(name);
		map.remove(key);
	}

	/**
	 * @see org.apache.commons.beanutils.DynaBean#set(java.lang.String, int,
	 *      java.lang.Object)
	 */
	public void set(String name, int index, Object value) {
		DynaProperty prop = getDynaClass().getDynaProperty(name);
		if (!prop.isIndexed()) {
			throw new IllegalArgumentException("Property [" + name + "] does not support indexed values");
		}
		List values = getIndexedValue(name);
		values.set(index, value);
		super.put(name, values);
	}

	/**
	 * @see org.apache.commons.beanutils.DynaBean#set(java.lang.String,
	 *      java.lang.Object)
	 */
	public void set(String name, Object value) {
		put(name, value);
	}

	/**
	 * @see org.apache.commons.beanutils.DynaBean#set(java.lang.String,
	 *      java.lang.String, java.lang.Object)
	 */
	public void set(String name, String key, Object value) {
		Map values = getMappedValue(name);
		values.put(key, value);
	}
	
	private Map getMappedValue(String name) {
		Object value = super.get(name);
		if (value instanceof Map) {
			return (Map) value;
		} else {
			throw new IllegalArgumentException(name + " is not a mapped property");
		}
	}

	private List getIndexedValue(String name) {
		Object value = super.get(name);
		if (value == null) {
			return new ArrayList();
		}
		
		if (value instanceof List) {
			return (List) value;
		} else {
			throw new IllegalArgumentException(name + " is not a List property");
		}
	}
	
	public SObjectDynaBean getNestedBean(String path) {
		Object value = get(path);
		if (value == null) {
			return null;
		}
		if (value instanceof SObjectDynaBean) {
			return (SObjectDynaBean)value;
		}
		return null;
	}
}
